#include "HLC_FP.hpp"

#ifdef DBG_TAG
#undef DBG_TAG
#endif
#ifdef DBG_LVL
#undef DBG_LVL
#endif

#define DBG_TAG     "hlc_fp"
#define DBG_LVL     DBG_LOG

extern "C"
{
#include <rtdbg.h>
}

using namespace std;

void HLC_FP::_hlc_fp_send_message(uint32_t data_len,uint8_t* data_buff)
{
    uart->CHIP_UART_send(data_len, data_buff);
}

chip_uart_message* HLC_FP::_hlc_fp_receive_message(uint32_t timeout)//使用后需要delete返回值
{
    return uart->CHIP_UART_read_receive(timeout);
}

uint8_t HLC_FP::_hlc_fp_protocol_count_checksum(uint32_t data_len, uint8_t * data_buff)
{
    uint32_t i = 0;
    uint8_t sum = 0;
    if (!data_buff)
    LOG_E("checksum input nullptr");
    for (i = 0; i < data_len; i++)
    {
        sum += data_buff[i];
    }
    return (uint8_t) ((~sum) + 1);
}

HLC_FP::HLC_FP(CHIP_UART* uart,CHIP_OUTPUT_PIN* power_pin,CHIP_INPUT_PIN* touch_pin,hlc_fp_device_type device_type,uint32_t fp_pwd)
{
    int i;
    if(!uart || !touch_pin || !power_pin)
    {
        LOG_E("input uart or touch_pin or power_pin is null");
        goto end;
    }
    if(uart->CHIP_UART_read_init_status() != chip_uart_status_ok)
        goto end;
    if(touch_pin->CHIP_INPUT_PIN_read_init_status() != chip_pin_status_ok)
        goto end;
    if(power_pin->CHIP_OUTPUT_read_init_status() != chip_pin_status_ok)
        goto end;

    this->uart = uart;
    this->touch_pin = touch_pin;
    this->power_pin = power_pin;

    switch(device_type)
    {
    case hlc_fp_device_type_FPM383:
        link_layer_frame_head[0] = 0xF1;
        link_layer_frame_head[1] = 0x1F;
        link_layer_frame_head[2] = 0xE2;
        link_layer_frame_head[3] = 0x2E;
        link_layer_frame_head[4] = 0xB6;
        link_layer_frame_head[5] = 0x6B;
        link_layer_frame_head[6] = 0xA8;
        link_layer_frame_head[7] = 0x8A;
        break;
    default:
        LOG_E("HLC_FP device type error");
        goto end;
        break;
    }
    rt_memset(app_layer_password, 0, 4);
    app_layer_password[0] |= (fp_pwd >>24);
    app_layer_password[1] |= (fp_pwd >>16);
    app_layer_password[2] |= (fp_pwd >>8);
    app_layer_password[3] |= (fp_pwd >>0);

    //创建锁
    serial_lock = rt_mutex_create("fp_lcok", RT_IPC_FLAG_FIFO);
    if(!serial_lock)
    {
        LOG_E("fp lock create fail");
        goto end;
    }

    //输出数据

    LOG_I("hlc fp fream head");
    for(i = 0; i < 8; i++)
    {
        rt_kprintf("<0x%.2X> ",link_layer_frame_head[i]);
    }
    rt_kprintf("\r\n");

    LOG_I("hlc fp password <0x%.4X>",fp_pwd);
    LOG_I("hlc fp init ok , config below");
    init_flag = hlc_fp_status_ok;
    return;
    end:
    LOG_E("hlc fp init fail");
    init_flag = hlc_fp_status_fail;
}

void HLC_FP::HLC_FP_waiting_for_good()
{
    while(HLC_FP_check_alive()!=hlc_fp_status_ok);
    LOG_I("fp good");
}

hlc_fp_status HLC_FP::HLC_FP_send_CMD(uint8_t CMD1,uint8_t CMD2,uint32_t app_data_len,uint8_t* app_data_buff)
{
    uint8_t checksum;
    uint8_t link_layer_frame_app_len[2] = {};
    uint32_t send_offset = 0;
    uint8_t* send_buff,*send_buff_temp;
    uint32_t send_buff_len = 0;
    if(!app_data_buff && app_data_len > 0)
    {
        LOG_E("app data buff cant be null");
        goto end;
    }

    send_buff = (uint8_t*)rt_malloc(11);
    if(!send_buff)
    {
        LOG_E("no mem for send cmd");
        goto end;
    }
    send_buff_len = 11;
    link_layer_frame_app_len[0] |= ((app_data_len+7) >>8);
    link_layer_frame_app_len[1] |= ((app_data_len+7) >>0);

    //生成帧头
    rt_memcpy(send_buff+send_offset, link_layer_frame_head, 8);//帧头
    send_offset += 8;
    rt_memcpy(send_buff+send_offset, link_layer_frame_app_len, 2);//应用数据长度
    send_offset += 2;
    checksum = _hlc_fp_protocol_count_checksum(send_offset,send_buff);
    rt_memcpy(send_buff+send_offset,&checksum , 1);//帧头校验和
    send_offset += 1;
    //到此处有11个数据
    //生成应用层
    send_buff_len +=7;
    send_buff_temp = (uint8_t*)rt_realloc(send_buff, send_buff_len);
    if(!send_buff_temp)
    {
        LOG_E("no mem for send cmd");
        goto end;
    }
    send_buff = send_buff_temp;

    rt_memcpy(send_buff+send_offset, app_layer_password, 4);//填充密码
    send_offset += 4;
    rt_memcpy(send_buff+send_offset, &CMD1, 1);//填充命令1
    send_offset += 1;
    rt_memcpy(send_buff+send_offset, &CMD2, 1);//填充命令2
    send_offset += 1;

    //扩充数据位
    if(app_data_len > 0)
    {
        send_buff_len +=app_data_len;
        send_buff_temp = (uint8_t*)rt_realloc(send_buff, send_buff_len);
        if(!send_buff_temp)
        {
            LOG_E("no mem for send cmd");
            goto end;
        }
        send_buff = send_buff_temp;

        //添加数据
        rt_memcpy(send_buff+send_offset, app_data_buff, app_data_len);
        send_offset += app_data_len;
    }



    //添加总校验
    checksum = _hlc_fp_protocol_count_checksum(send_offset,send_buff);
    rt_memcpy(send_buff+send_offset, &checksum, 1);
    send_offset += 1;

    //测试
//    LOG_D("send buff");
//    for(int i = 0; i< send_buff_len;i++)
//    {
//        rt_kprintf("<0x%.2X> ",send_buff[i]);
//        if(i == 10 || i == send_buff_len-1)
//            rt_kprintf("\r\n");
//    }
    //发送
    _hlc_fp_send_message(send_buff_len,send_buff);
    if(send_buff)
        rt_free(send_buff);

    return hlc_fp_status_ok;
    end:
    return hlc_fp_status_fail;
}

hlc_fp_status HLC_FP::_hlc_fp_check_response(chip_uart_message* back_msg)
{
    uint32_t error_code;
    uint8_t checksum;
    hlc_fp_status status = hlc_fp_status_fail;
    if(!back_msg)
    {
        LOG_E("fp msg is null");
        goto end;
    }
    if(back_msg->now_end_pos<22)
    {
        LOG_E("fp msg length error, msg length is <%u>",back_msg->now_end_pos);
        goto end;
    }

    checksum = _hlc_fp_protocol_count_checksum(back_msg->now_end_pos-1, back_msg->message);
    if(checksum != back_msg->message[back_msg->now_end_pos-1])
    {
        LOG_E("fp msg checksum error");
        status = hlc_fp_status_checksum_error;
        goto end;
    }
    error_code = 0;
    error_code |= back_msg->message[17]<<24;
    error_code |= back_msg->message[18]<<16;
    error_code |= back_msg->message[19]<<8;
    error_code |= back_msg->message[20]<<0;
    switch(error_code)
    {
    case 0:
        status = hlc_fp_status_ok;
        break;
    case 4:
        LOG_W("fp busy");
        status = hlc_fp_status_system_busy;
        break;
    default:
        status = hlc_fp_status_system_error;
        LOG_E("fp system error,error code <0x%.8X>",error_code);
        break;
    }
    end:
    return status;
}

hlc_fp_status HLC_FP::HLC_FP_check_alive()
{
    chip_uart_message * msg=nullptr;
    if(HLC_FP_send_CMD(0x03,0x03,0,NULL) != hlc_fp_status_ok)
    {
        LOG_E("check alive send fail");
        goto end;
    }
    msg = _hlc_fp_receive_message(100);
    if(_hlc_fp_check_response(msg) != hlc_fp_status_ok)
    {
        LOG_E("check alive check fail");
        goto end;
    }

    delete msg;
    return hlc_fp_status_ok;
    end:
    delete msg;
    return hlc_fp_status_fail;
}

hlc_fp_status HLC_FP::HLC_FP_stop_reg_or_match_fp()
{
    chip_uart_message * msg=nullptr;
    if(HLC_FP_send_CMD(0x01,0x15,0,NULL) != hlc_fp_status_ok)
    {
        LOG_E("stop reg fp send fail");
        goto end;
    }
    msg = _hlc_fp_receive_message(100);
    if(_hlc_fp_check_response(msg) != hlc_fp_status_ok)
    {
        LOG_E("stop reg fp check fail");
        goto end;
    }

    LOG_I("stop reg fp send ok");
    delete msg;
    return hlc_fp_status_ok;
    end:
    delete msg;
    return hlc_fp_status_fail;
}

hlc_fp_status HLC_FP::HLC_FP_auto_reg_fp()
{
    int i;
    uint8_t pro;
    hlc_fp_status flag;
    chip_uart_message * msg=nullptr;
    uint8_t buff[]={0x01,0x06,0xFF,0xFF};

    if(HLC_FP_send_CMD(0x01,0x18,4,buff) != hlc_fp_status_ok)
    {
        LOG_E("auto reg send fail");
        goto end;
    }
    i = 1;
    do
    {
        delete msg;
        msg = nullptr;
        HLC_FP_led_control(0x04,0x04,0x22,0x22,0x32);//蓝灯闪亮开始录制
        msg = _hlc_fp_receive_message(10000);

        flag = _hlc_fp_check_response(msg);
        if( flag == hlc_fp_status_fail)
        {
            LOG_E("auto reg check fail,times <%d>",i);
            HLC_FP_stop_reg_or_match_fp();
            goto end;
        }
        else if(flag == hlc_fp_status_system_busy)
        {
            LOG_W("auto reg busy,times <%d>",i);
        }
        else if(flag == hlc_fp_status_system_error)
        {
            LOG_E("auto reg error,times <%d>",i);
            if(msg->message[20] == 0x0F)
            {
                HLC_FP_stop_reg_or_match_fp();
                LOG_W("this fp have been reged!");
                break;
            }
            HLC_FP_led_control(0x01,0x02,0x22,0x22,0x00);//红灯闪亮表示非正常录入
            rt_thread_mdelay(1000);

        }
        else
        {
            pro = msg->message[24];
            LOG_I("auto reg got!,times <%d> pro <%u>",i,pro);
            i++;
            HLC_FP_led_control(0x01,0x03,0x22,0x22,0x00);//黄灯闪亮表示正常录入
            rt_thread_mdelay(1000);
        }
        LOG_D("msg->message[21] <%.2X>",msg->message[21]);

    }while(msg->message[21] != 0xEF);



    LOG_I("auto reg finished");
    delete msg;
    return hlc_fp_status_ok;
    end:
    LOG_E("auto reg fail");
    delete msg;
    return hlc_fp_status_fail;
}

hlc_fp_status HLC_FP::HLC_FP_delete_all_fp()
{
    chip_uart_message * msg=nullptr;
    uint8_t buff[]={0x01,0x00,0x01};

    if(HLC_FP_send_CMD(0x01,0x31,3,buff) != hlc_fp_status_ok)
    {
        LOG_E("delete all fp send fail");
        goto end;
    }
    msg = _hlc_fp_receive_message(500);
    if(_hlc_fp_check_response(msg) != hlc_fp_status_ok)
    {
        LOG_E("delete all fp check fail");
        goto end;
    }

    delete msg;
    return hlc_fp_status_ok;
    end:
    delete msg;
    return hlc_fp_status_fail;
}

hlc_fp_status HLC_FP::HLC_FP_check_fp_on_pos()
{
    hlc_fp_status flag;
    chip_uart_message * msg=nullptr;
    if(HLC_FP_send_CMD(0x01,0x35,0,NULL) != hlc_fp_status_ok)
    {
        LOG_E("check fp on pos send fail");
        goto end;
    }
    msg = _hlc_fp_receive_message(100);
    flag = _hlc_fp_check_response(msg);
    if( flag == hlc_fp_status_fail)
    {
        LOG_E("check fp on pos check fail");
        HLC_FP_stop_reg_or_match_fp();
        goto end;
    }
    else if(flag == hlc_fp_status_system_busy)
    {
        LOG_W("check fp on pos busy");
    }
    else if(flag == hlc_fp_status_system_error)
    {
        LOG_E("check fp on pos error");
        goto end;
    }
    else
    {
        if(msg->message[21] == 0x01)
        {
            LOG_I("fp on pos");
        }else
        {
//            LOG_W("no fp on pos");
            goto end;
        }

    }
    delete msg;
    return hlc_fp_status_ok;
    end:
    delete msg;
    return hlc_fp_status_fail;
}
hlc_fp_status HLC_FP::HLC_FP_match_fp()
{
    hlc_fp_status flag;
    chip_uart_message * msg=nullptr;
    if(HLC_FP_send_CMD(0x01,0x23,0,NULL) != hlc_fp_status_ok)
    {
        LOG_E("match fp send fail");
        goto end;
    }

    HLC_FP_led_control(0x01,0x07,0x22,0x22,0x00);//白灯亮等待指纹
    msg = _hlc_fp_receive_message(10000);
    flag = _hlc_fp_check_response(msg);
    if( flag == hlc_fp_status_fail)
    {
        LOG_E("match fp check fail");
        HLC_FP_stop_reg_or_match_fp();
        goto end;
    }
    else if(flag == hlc_fp_status_system_busy)
    {
        LOG_W("match fp busy");
    }
    else if(flag == hlc_fp_status_system_error)
    {
        LOG_E("match fp error");
        HLC_FP_led_control(0x04,0x02,0x12,0x12,0x03);//红灯闪亮表示非正常
        rt_thread_mdelay(1000);
        goto end;
    }
    else
    {
        if(msg->message[22] == 0x01)
        {
            LOG_I("fp matched");
            HLC_FP_led_control(0x04,0x01,0x12,0x12,0x03);//绿灯闪亮表示正常
//            LOG_D("match id H<%.2X> L<%.2X>",msg->message[25],msg->message[26]);
            HLC_FP_auto_update_fp(msg->message[25],msg->message[26]);//更新指纹
            rt_thread_mdelay(900);
        }else
        {
            LOG_W("no fp matched");
            HLC_FP_led_control(0x04,0x02,0x12,0x12,0x03);//红灯闪亮表示非正常
            rt_thread_mdelay(900);
            goto end;
        }

    }

    delete msg;
    return hlc_fp_status_ok;
    end:
    delete msg;
    return hlc_fp_status_fail;
}

hlc_fp_status HLC_FP::HLC_FP_auto_update_fp(uint8_t ID_H,uint8_t ID_L)
{
    chip_uart_message * msg=nullptr;
    uint8_t buff[]={ID_H,ID_L};
    //自动更新
    if(HLC_FP_send_CMD(0x01,0x16,2,buff) != hlc_fp_status_ok)
    {
        LOG_E("auto update fp send fail");
        goto end;
    }
    msg = _hlc_fp_receive_message(500);
    if(_hlc_fp_check_response(msg) != hlc_fp_status_ok)
    {
        LOG_E("auto update fp check fail");
        goto end;
    }
    //查看自动更新
    if(HLC_FP_send_CMD(0x01,0x17,0,NULL) != hlc_fp_status_ok)
    {
        LOG_E("check auto update fp send fail");
        goto end;
    }
    msg = _hlc_fp_receive_message(500);
    if(_hlc_fp_check_response(msg) != hlc_fp_status_ok)
    {
        LOG_E("check auto update fp check fail");
        goto end;
    }

    delete msg;
    return hlc_fp_status_ok;
    end:
    delete msg;
    return hlc_fp_status_fail;
}


hlc_fp_status HLC_FP::HLC_FP_sleep()
{
    chip_uart_message * msg=nullptr;
    uint8_t buff[]={0x00};
    if(HLC_FP_send_CMD(0x02,0x0C,1,buff) != hlc_fp_status_ok)
    {
        LOG_E("sleep send fail");
        goto end;
    }
    msg = _hlc_fp_receive_message(500);
    if(_hlc_fp_check_response(msg) != hlc_fp_status_ok)
    {
        LOG_E("sleep check fail");
        goto end;
    }
    else
    {
        LOG_I("go in sleep normol");
    }

    delete msg;
    return hlc_fp_status_ok;
    end:
    delete msg;
    return hlc_fp_status_fail;
}

hlc_fp_status HLC_FP::HLC_FP_reset()
{
    chip_uart_message * msg=nullptr;
    power_pin->CHIP_OUTPUT_PIN_write(chip_pin_level_LOW);
    rt_thread_mdelay(50);
    power_pin->CHIP_OUTPUT_PIN_write(chip_pin_level_HIGH);
    HLC_FP_waiting_for_good();

    if(HLC_FP_send_CMD(0x02,0x02,0,NULL) != hlc_fp_status_ok)
    {
        LOG_E("reset send fail");
        goto end;
    }
    msg = _hlc_fp_receive_message(500);
    if(_hlc_fp_check_response(msg) != hlc_fp_status_ok)
    {
        LOG_E("reset check fail");
        goto end;
    }
    else
    {
        LOG_I("fp reseted!");
    }
    HLC_FP_waiting_for_good();
//    HLC_FP_sleep();

    delete msg;
    return hlc_fp_status_ok;
    end:
    delete msg;
    return hlc_fp_status_fail;
}

hlc_fp_status HLC_FP::HLC_FP_led_control(uint8_t mode,uint8_t color,uint8_t pra1,uint8_t pra2,uint8_t pra3)
{
    chip_uart_message * msg=nullptr;
    uint8_t buff[]={mode,color,pra1,pra2,pra3};

    if(HLC_FP_send_CMD(0x02,0x0F,5,buff) != hlc_fp_status_ok)
    {
        LOG_E("check led control send fail");
        goto end;
    }
    msg = _hlc_fp_receive_message(500);
    if(_hlc_fp_check_response(msg) != hlc_fp_status_ok)
    {
        LOG_E("check led control check fail");
        goto end;
    }

    delete msg;
    return hlc_fp_status_ok;
    end:
    delete msg;
    return hlc_fp_status_fail;
}

hlc_fp_status HLC_FP::HLC_FP_read_init_status()
{
    return init_flag;
}

void HLC_FP::HLC_FP_take_mutex()
{
    rt_mutex_take(serial_lock,RT_WAITING_FOREVER);
}
void HLC_FP::HLC_FP_release_mutex()
{
    rt_mutex_release(serial_lock);
}
